package sebastiankerckhof.render.rasterize;

import sebastiankerckhof.CgPanel;
import sebastiankerckhof.math.Color3f;
import sebastiankerckhof.math.Matrix4f;
import sebastiankerckhof.math.Point3f;
import sebastiankerckhof.math.Vector3f;
import sebastiankerckhof.render.Renderer;
import sebastiankerckhof.scene.FieldOfView;
import sebastiankerckhof.scene.Scene;
import sebastiankerckhof.scene.geometry.Triangle;
import sebastiankerckhof.scene.geometry.Vertex;
import sebastiankerckhof.scene.lighting.PointLight;
import sebastiankerckhof.scene.material.DiffuseMaterial;

public class Rasterizer implements Renderer{
	
	Scene scene;
	CgPanel panel;
	FieldOfView fov;

	@Override
  public void render(Scene scene, CgPanel panel, FieldOfView fov) {
		this.fov = fov;
		this.scene = scene;
		this.panel = panel;
		
		Matrix4f trans = buildTransformationMatrix();
	
		float[][] zBuffer = new float[fov.nx][fov.ny];
		for(int i=0; i<fov.nx; i++){
			for(int j=0; j<fov.ny; j++){
				zBuffer[i][j] = Float.MAX_VALUE;
			}
		}
		
		
	  for(Triangle t : scene.getTriangles()){
	  	/*
	  	try {
	      Thread.sleep(100);
      } catch (InterruptedException e) {
	      // TODO Auto-generated catch block
	      e.printStackTrace();
      }
	  	*/
	  	Color3f colorA, colorB, colorC;
	  	PointLight p = (PointLight) scene.lights.get(0);
	  	Color3f base = p.color //
  				.scale(p.intensity) //cl
  				.multiply(((DiffuseMaterial)t.material).color);//cl.cr
	  			
	

	  	colorA = calculateColor(base, t.a);
	  	colorB = calculateColor(base, t.b);
	  	colorC = calculateColor(base, t.c);

	  	float az = t.a.position.z;
	  	float bz = t.b.position.z;
	  	float cz = t.c.position.z;
	  	
	  	t.transform(trans, trans.tranpose());
	  	//t.a.position = trans.transform(t.a.position);
	  	//t.b.position = trans.transform(t.b.position);
	  	//t.c.position = trans.transform(t.c.position);
	  	
	  	int xmin = (int) Math.floor(t.xMin());
	  	int xmax = (int) Math.ceil(t.xMax());
	  	int ymin = (int) Math.floor(t.yMin());
	  	int ymax = (int) Math.ceil(t.yMax());
	  	
	  	//TODO/ verbeteringen p. 169
	  	
	  	for(int x = xmin; x <= xmax; x++){
	  		for(int y = ymin; y <= ymax; y++){
	  		
	  			
	  			//TODO: incremental & clipping
	  			float alpha = fab(t.b.position,t.c.position,x,y) / fab(t.b.position,t.c.position,t.a.position.x,t.a.position.y);
	  			float beta = fab(t.c.position,t.a.position,x,y) / fab(t.c.position,t.a.position,t.b.position.x,t.b.position.y);
	  			float gamma = fab(t.a.position,t.b.position,x,y) / fab(t.a.position,t.b.position,t.c.position.x,t.c.position.y);
	  			
	  			if(alpha > 0 && beta > 0 && gamma > 0){
	  				//TODO: shading
	  				float z = ((alpha*t.a.position.z + beta * t.b.position.z + gamma * t.c.position.z)/(alpha+beta+gamma));
	  				
	  				if(zBuffer[x][y] > z){
	  					System.out.println(z);
  	  				zBuffer[x][y] = z;
  	  				Color3f color = colorA.scale(alpha)
  	  						.plus(colorB.scale(beta))
  	  						.plus(colorC.scale(gamma));
  	  				
  	  				panel.drawPixel(x, y, color.x, color.y, color.z);
	  				}else{
	  					System.out.println(z + " " +zBuffer[x][y]);
	  				}
	  			}
	  		}
	  	}
	  }
	  
  }
	
	public Color3f calculateColor(Color3f base, Vertex v){
		Color3f result = base;
		Vector3f direction = ((PointLight) scene.lights.get(0)).position.subtract(v.position);
		float scale = v.normal.dotProduct(direction.normalize());// n.l
		scale = Math.max(0, -scale);// max(0,n.l)
		result = result.scale(scale);//cl.cr.max(0,n.l)
		result = result.clamp();
		return result;
	}
	
	public float fab(Point3f a, Point3f b, float x, float y){
		return (a.y - b.y)*x + (b.x - a.x)*y + a.x*b.y - b.x*a.y;
	}
	
	public Matrix4f buildTransformationMatrix(){
		Matrix4f m = Matrix4f.getMvp(fov.nx, fov.ny)
				.multiply(Matrix4f.getMper(fov.right, fov.left, fov.top, fov.bottom, fov.near, (int) fov.far))
				.multiply(Matrix4f.getMcam(scene.camera.u, scene.camera.v, scene.camera.w, scene.camera.e));
		return m;
	}

}
